﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Remoting.Messaging;

using System.Reflection;
using MessageCallAspect.Inspector.Request;
using MessageCallAspect.Inspector.Response;
using MessageCallAspect.Inspector.MessageSink;
using System.Diagnostics;

namespace MessageCallAspect.Inspector.Aspect.Trace
{
    public class TraceMessageSink : SimpleMessageInspector
    {
        #region fields

        private readonly TraceListener m_TraceListener;

        #endregion

        #region ctor

        public TraceMessageSink(IModuleContext context, object target, IMessageSink nextSink)
            : base(context, target, nextSink)
        {
            m_TraceListener = new ConsoleTraceListener();
        }

        #endregion

        protected virtual TraceListener TraceListener
        {
            get
            {
                return m_TraceListener;
            }
        }

        protected override void OnBeforeInvoke(IMessageRequest request)
        {
            base.OnBeforeInvoke(request);
            StringBuilder sb = new StringBuilder();

            sb.AppendFormat("TraceAspect - Before invoke : {0}{1}.{2}(", request.Method.ReturnParameter, request.Target.GetType().Name, request.Method.Name);
            // Loop through the [in] parameters
            ParameterInfo[] parameters = request.Method.GetParameters();
            for (int i = 0; i < parameters.Length; ++i)
            {
                if (i > 0)
                    sb.Append(", ");
                
                sb.AppendFormat("{0} = {1}", parameters[i].Name, request.Arguments[i]);
            }
            sb.Append(")");
            TraceListener.WriteLine(sb);
        }

        protected override void OnAfterInvoke(IMessageRequest request, IMessageResponse response)
        {
            base.OnAfterInvoke(request, response);
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("TraceAspect - After invoke  : {0}{1}.{2}(", request.Method.ReturnParameter, request.Target.GetType().Name, request.Method.Name);
            //Loop through all the [out] parameters
            ParameterInfo[] parameters = request.Method.GetParameters();

            int outParamIndex = 0;
            for (int i = 0; i < parameters.Length; ++i)
            {
                if (i > 0)
                    sb.Append(", ");
                
                if (parameters[i].IsOut && response.OutArgs.Length > outParamIndex)
                    sb.AppendFormat("<out>{0} = {1}", parameters[i].Name, response.OutArgs[outParamIndex++]);
                else
                    sb.AppendFormat("{0} = {1}", parameters[i].Name, request.Arguments[i]);
            }

            if (response.ReturnValue != null && response.ReturnValue.GetType() != typeof(void))
                sb.AppendFormat(" returned [{0}]", response.ReturnValue);
            
            if (response.Exception != null)
                sb.AppendFormat("Exception was thrown: {0}", response.Exception);

            sb.AppendFormat(") took {0} seconds \n", response.Duration.TotalSeconds);
            TraceListener.WriteLine(sb);
        }
    }
   
}
